﻿using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using UnityTouchTable.Runtime;

namespace UnityTouchTable.Editor
{
    [CustomEditor(typeof(UnityTouchTableEntry), true)]
    [CanEditMultipleObjects]
    public class UnityTouchTableEntryEditor : TouchTableInspector
    {
        #region Field
        private SerializedProperty m_LicenseData;

        private SerializedProperty m_ProcessMode;

        private SerializedProperty m_Simulation;
        private SerializedProperty m_MinMoveDistance;
        private SerializedProperty m_MinRotateAngle;
        private SerializedProperty m_ForcedUpdate;

        private SerializedProperty m_LogHelper;
        private SerializedProperty m_EnableLog;

        private SerializedProperty m_InputHelper;

        private SerializedProperty m_Marks = null;

        private ReorderableList m_MarkArray;

        /// <summary>
        /// 是否显示许可数据
        /// </summary>
        private bool m_ShowLicenseData;

        /// <summary>
        /// 是否显示处理模式
        /// </summary>
        private bool m_ShowProcessMode;

        /// <summary>
        /// 是否显示参数
        /// </summary>
        private bool m_ShowParameter;

        /// <summary>
        /// 是否显示日志
        /// </summary>
        private bool m_ShowLog;

        /// <summary>
        /// 是否显示触摸输入
        /// </summary>
        private bool m_ShowInput;

        /// <summary>
        /// 日志类型名称
        /// </summary>
        private List<string> m_LogTypeNames = new List<string>();

        /// <summary>
        /// 日志索引
        /// </summary>
        private int m_LogIndex = 0;

        /// <summary>
        /// 触摸输入类型名称
        /// </summary>
        private List<string> m_InputTypeNames = new List<string>();

        /// <summary>
        /// 触摸输入索引
        /// </summary>
        private int m_InputIndex = 0;
        #endregion

        [MenuItem("GameObject/TouchTable/UnityTouchTableEntry", false, 1)]
        public static void CreateUnityTouchTableEntry()
        {
            GameObject go = new GameObject("UnityTouchTableEntry");
            go.AddComponent<UnityTouchTableEntry>();
            Selection.activeGameObject = go;
        }

        private void OnEnable()
        {
            //许可数据
            this.m_LicenseData = this.serializedObject.FindProperty("m_LicenseData");

            //事件处理模式
            this.m_ProcessMode = this.serializedObject.FindProperty("m_ProcessMode");

            //参数
            this.m_Simulation = this.serializedObject.FindProperty("m_Simulation");
            this.m_MinMoveDistance = this.serializedObject.FindProperty("m_MinMoveDistance");
            this.m_MinRotateAngle = this.serializedObject.FindProperty("m_MinRotateAngle");
            this.m_ForcedUpdate = this.serializedObject.FindProperty("m_ForcedUpdate");

            //Log
            this.m_LogHelper = this.serializedObject.FindProperty("m_LogHelper");
            this.m_EnableLog = this.serializedObject.FindProperty("m_EnableLog");

            //输入
            this.m_InputHelper = this.serializedObject.FindProperty("m_InputHelper");

            //标记项
            this.m_Marks = this.serializedObject.FindProperty("m_Marks");
            this.m_MarkArray = new ReorderableList(this.serializedObject, this.m_Marks, true, true, true, true);
            this.m_MarkArray.drawHeaderCallback = this.OnMarkArrayDrawHead;
            this.m_MarkArray.drawElementCallback = this.OnMarkArrayDrawElement;

            //name
            string entryName = typeof(UnityTouchTableEntry).Name;
            if (!this.serializedObject.targetObject.name.Equals(entryName))
                this.serializedObject.targetObject.name = entryName;

            this.RefreshTypeNames();
        }

        public override void OnInspectorGUI()
        {
            this.serializedObject.Update();

            if (!EditorApplication.isPlaying)
            {
                this.DrawIcon();
                this.DrawLicenseData();
                this.DrawProcessMode();
                this.DrawParameter();
                this.DrawLog();
                this.DrawInput();
            }
            else
                EditorGUILayout.LabelField("运行时不允许修改参数。。。");

            this.serializedObject.ApplyModifiedProperties();
        }

        /// <summary>
        /// 绘制Logo
        /// </summary>
        private void DrawIcon()
        {
            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            Texture2D icon = Resources.Load<Texture2D>("jsuto");
            if (icon != null)
                GUILayout.Label(new GUIContent(icon), GUILayout.MaxWidth(72.8f * 1.2f), GUILayout.Height(51.4f * 1.2f));
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            GUIStyle style = new GUIStyle();
            style.richText = true;
            GUI.color = Color.black;
            GUILayout.Label("<b><size=20>家速通</size></b>", style);
            GUI.color = Color.white;
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space(8.8f);

            string url = "http://www.jsuto.cn/";
            if (GUILayout.Button(url, GUILayout.ExpandWidth(true)))
                Application.OpenURL(url);
            EditorGUILayout.Space(20.0f);
        }

        /// <summary>
        /// 绘制许可数据
        /// </summary>
        private void DrawLicenseData()
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            EditorGUI.indentLevel++;
            this.m_ShowLicenseData = EditorGUILayout.BeginFoldoutHeaderGroup(this.m_ShowLicenseData, "许可数据");

            if (this.m_ShowLicenseData)
                this.m_LicenseData.stringValue = EditorGUILayout.TextArea(this.m_LicenseData.stringValue, GUILayout.MinHeight(300));

            EditorGUILayout.EndFoldoutHeaderGroup();
            EditorGUI.indentLevel--;
            EditorGUILayout.EndVertical();
        }

        /// <summary>
        /// 绘制处理模式
        /// </summary>
        private void DrawProcessMode()
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            EditorGUI.indentLevel++;
            this.m_ShowProcessMode = EditorGUILayout.BeginFoldoutHeaderGroup(this.m_ShowProcessMode, "事件处理模式");
            if (this.m_ShowProcessMode)
            {
                EditorGUILayout.PropertyField(this.m_ProcessMode, new GUIContent("处理模式"));

                switch ((ProcessMode)this.m_ProcessMode.enumValueIndex)
                {
                    case ProcessMode.Internal:
                        {
                            EditorGUILayout.HelpBox("内置处理模式,使用MarkerItem处理...", MessageType.None);
                            EditorGUILayout.Space(6.0f);
                            this.m_MarkArray.DoLayoutList();
                        }
                        break;
                    case ProcessMode.Custom:
                        EditorGUILayout.HelpBox("自定义处理模式，订阅相关事件自行处理...", MessageType.None);
                        break;
                    default:
                        break;
                }
            }
            EditorGUILayout.EndFoldoutHeaderGroup();
            EditorGUI.indentLevel--;
            EditorGUILayout.EndVertical();
        }

        /// <summary>
        /// 绘制参数
        /// </summary>
        private void DrawParameter()
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            EditorGUI.indentLevel++;
            this.m_ShowParameter = EditorGUILayout.BeginFoldoutHeaderGroup(this.m_ShowParameter, "参数");
            if (this.m_ShowParameter)
            {
                EditorGUILayout.PropertyField(this.m_Simulation, new GUIContent("模拟模式？"));
                if (this.m_Simulation.boolValue)
                    EditorGUILayout.HelpBox("用于编辑器模式开发使用，需配合模拟器使用。", MessageType.None);

                EditorGUILayout.Slider(this.m_MinMoveDistance, 0.0f, 5.0f, new GUIContent("最小移动距离"));
                EditorGUILayout.Slider(this.m_MinRotateAngle, 0.0f, 5.0f, new GUIContent("最小旋转角度"));
                EditorGUILayout.PropertyField(this.m_ForcedUpdate, new GUIContent("是否强制更新？"));
                if (this.m_ForcedUpdate.boolValue)
                    EditorGUILayout.HelpBox("将忽略安全校验进行计算，建议关闭。", MessageType.Warning);
            }
            EditorGUILayout.EndFoldoutHeaderGroup();
            EditorGUI.indentLevel--;
            EditorGUILayout.EndVertical();
        }

        /// <summary>
        /// 绘制日志
        /// </summary>
        private void DrawLog()
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            EditorGUI.indentLevel++;
            this.m_ShowLog = EditorGUILayout.BeginFoldoutHeaderGroup(this.m_ShowLog, "日志");
            if (this.m_ShowLog)
            {
                EditorGUILayout.PropertyField(this.m_EnableLog, new GUIContent("开启日志"));
                if (this.m_EnableLog.boolValue)
                {
                    if (this.m_LogTypeNames.Count > 0)
                    {
                        int selectIndex = EditorGUILayout.Popup("日志", this.m_LogIndex, this.m_LogTypeNames.ToArray());
                        if (selectIndex != this.m_LogIndex)
                        {
                            this.m_LogIndex = selectIndex;
                            this.m_LogHelper.stringValue = this.m_LogTypeNames[this.m_LogIndex];
                        }
                    }
                    else
                        EditorGUILayout.HelpBox("未查找到实现ILogHelper的日志类。。。", MessageType.Warning);
                }
            }
            EditorGUILayout.EndFoldoutHeaderGroup();
            EditorGUI.indentLevel--;
            EditorGUILayout.EndVertical();
        }

        /// <summary>
        /// 绘制触摸输入
        /// </summary>
        private void DrawInput()
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            EditorGUI.indentLevel++;
            this.m_ShowInput = EditorGUILayout.BeginFoldoutHeaderGroup(this.m_ShowInput, "触摸输入");
            if (this.m_ShowInput)
            {
                if (this.m_InputTypeNames.Count > 0)
                {
                    int selectIndex = EditorGUILayout.Popup("触摸输入", this.m_InputIndex, this.m_InputTypeNames.ToArray());
                    if (selectIndex != this.m_InputIndex)
                    {
                        this.m_InputIndex = selectIndex;
                        this.m_InputHelper.stringValue = this.m_InputTypeNames[this.m_InputIndex];
                    }

                    if (this.m_InputHelper.stringValue.EndsWith("MouseInput"))
                        EditorGUILayout.HelpBox("不要使用鼠标输入，鼠标输入只检测鼠标，不检测触摸点。。。", MessageType.Error);
                }
                else
                    EditorGUILayout.HelpBox("未查找到实现BaseInputSource的触摸类。。。", MessageType.Warning);
            }
            EditorGUILayout.EndFoldoutHeaderGroup();
            EditorGUI.indentLevel--;
            EditorGUILayout.EndVertical();
        }

        /// <summary>
        /// 标记项绘制标题时
        /// </summary>
        /// <param name="rect"></param>
        private void OnMarkArrayDrawHead(Rect rect) => GUI.Label(rect, "MarkItems");

        /// <summary>
        /// 当绘制元素时
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="index"></param>
        /// <param name="isActive"></param>
        /// <param name="isFocused"></param>
        private void OnMarkArrayDrawElement(Rect rect, int index, bool isActive, bool isFocused)
        {
            SerializedProperty itemData = this.m_MarkArray.serializedProperty.GetArrayElementAtIndex(index);
            EditorGUI.PropertyField(rect, itemData, GUIContent.none);
        }

        protected override void OnCompileComplete()
        {
            base.OnCompileComplete();

            this.RefreshTypeNames();
        }

        private void RefreshTypeNames()
        {
            this.m_LogTypeNames.Clear();
            this.m_InputTypeNames.Clear();
            this.m_LogTypeNames.AddRange(Type.GetRuntimeTypeNames(typeof(TouchTable.Debug.ILogHelper)));
            this.m_InputTypeNames.AddRange(Type.GetRuntimeTypeNames(typeof(TouchTable.Input.BaseInputSource)));

            if (this.m_LogTypeNames.Count > 0)
            {
                if (string.IsNullOrEmpty(this.m_LogHelper.stringValue))
                {
                    this.m_LogIndex = 0;
                    this.m_LogHelper.stringValue = this.m_LogTypeNames[0];
                }
                else
                {
                    this.m_LogIndex = this.m_LogTypeNames.IndexOf(this.m_LogHelper.stringValue);
                    if (this.m_LogIndex <= 0)
                    {
                        this.m_LogIndex = 0;
                        this.m_LogHelper.stringValue = this.m_LogTypeNames[0];
                    }
                }
            }
            else
            {
                this.m_LogIndex = 0;
                this.m_LogHelper.stringValue = string.Empty;
            }

            if (this.m_InputTypeNames.Count > 0)
            {
                if (string.IsNullOrEmpty(this.m_InputHelper.stringValue))
                {
                    this.m_InputIndex = 0;
                    this.m_InputHelper.stringValue = this.m_InputTypeNames[0];
                }
                else
                {
                    this.m_InputIndex = this.m_InputTypeNames.IndexOf(this.m_InputHelper.stringValue);
                    if (this.m_InputIndex <= 0)
                    {
                        this.m_InputIndex = 0;
                        this.m_InputHelper.stringValue = this.m_InputTypeNames[0];
                    }
                }
            }
            else
            {
                this.m_InputIndex = 0;
                this.m_InputHelper.stringValue = string.Empty;
            }
        }
    }
}